/*
 * ap.c
 *
 *  Created on: 2025.4.3
 *      Author: TracyHenry
 */
/*ESP8266 WIFI Station 代码*/

#include "ap.h"
#include "deviceManage.h"
#define max(a,b) ((a)>(b)?(a):(b))  /**< Find the maximum of 2 numbers. */
#define MAX_CLIENT_NUMBER 1
#define WEB_SERVER_PORT 80
#define STOP_TIMER 120000
#define BUFFER_MAX 128

#define RESPONSE_OK "{\"result\":1}"

#define RESPONSE_ERR_2 "{\"result\":2}"

#define RESPONSE_ERR_3 "{\"result\":3}"

static xQueueHandle QueueStop = NULL;
static xQueueHandle RCVQueueStop = NULL;

const static char *wifi = "myssid";

void task_ap(void* arg)
{
    wifi_config_t * sta_config;
    bool ValueFromReceiveMasterNoConnect=FALSE;
    bool flag_rev_wifi = FALSE;
    portBASE_TYPE xStatus;

    if (QueueStop == NULL)
    QueueStop = xQueueCreate(1,1);

    if (RCVQueueStop == NULL)
    RCVQueueStop = xQueueCreate(1,1);

    char *rx_buffer = (char*)malloc(BUFFER_MAX);
    char *addr_str = (char*)malloc(BUFFER_MAX);
    for(;;)
	{

        xStatus = xQueueReceive(QueueStop,&ValueFromReceiveMasterNoConnect,0);
        if ( pdPASS == xStatus && TRUE == ValueFromReceiveMasterNoConnect){
            printf("webserver_recv_thread rcv exit signal!\n");
            break;
        }

		//使用IPV4
        struct sockaddr_in destAddr;	//处理网络通信地址的结构体(服务器)
        destAddr.sin_addr.s_addr = htonl(INADDR_ANY);	//把本机字节顺序转化为网络字节顺序
        destAddr.sin_family = AF_INET;		//domain:（TCP/IP – IPv4）
        destAddr.sin_port = htons(WEB_SERVER_PORT);		//将主机字节顺序转换为网络字节顺序

        
        inet_ntoa_r(destAddr.sin_addr, addr_str, BUFFER_MAX - 1);	//转换IP地址到ASIIC字符串的函数
    //===================================================================		
        int listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);	//返回状态码
    
    //ESP_LOGI == printf
        if (listen_sock < 0) {		//返回-1表示失败，其他值参考:https://blog.csdn.net/sstnba/article/details/83380656
            printf("Unable to create socket: errno %d\n", errno);
            //break;
        }
        printf("Socket created\n");		//返回正常值说明Socket已经建立起来了
        
        int err = bind(listen_sock, (struct sockaddr *)&destAddr, sizeof(destAddr));	//把一个本地协议地址赋予一个套接字
        //返回值表示绑定操作是否成功，0表示成功， -1表示不成功。函数的返回值千万不要忽视，上次就被人说了。
        if (err != 0) {
            printf("Socket unable to bind: errno %d\n", errno);
            //break;
        }
        printf("Socket binded\n");
    
        err = listen(listen_sock, 1);		//设置监听和队列数
        if (err != 0) {
            printf("Error occured during listen: errno %d\n", errno);
            break;
        }
        printf("Socket listening\n");	//成功监听
    //===================================================================		
        //使用IPV4
        struct sockaddr_in sourceAddr;	//处理网络通信地址的结构体(客户端)
        
        uint32_t addrLen = sizeof(sourceAddr);	//地址大小
        int sock = accept(listen_sock, (struct sockaddr *)&sourceAddr, &addrLen);
        if (sock < 0) {
            printf("Unable to accept connection: errno %d", errno);
            break;
        }
        printf("Socket accepted\n");  	//阻塞处理-进行握手连接  
//===================================================================		
    
        while (1) //处于监听状态
        {

            xStatus = xQueueReceive(RCVQueueStop,&ValueFromReceiveMasterNoConnect,0);
            if ( pdPASS == xStatus && TRUE == ValueFromReceiveMasterNoConnect){
                printf("webserver_recv_thread rcv exit signal!\n");
                break;
            }

            int len = recv(sock, rx_buffer, BUFFER_MAX  - 1, 0);	//从TCP连接的另一端接收数据
            // Error occured during receiving
            if (len < 0){	//recv在copy时出错了
                printf("recv failed: errno %d", errno);
                break;
            }
            // Connection closed
            else if (len == 0) {	//等待协议接收数据时网络中断了
                printf("Connection closed");
                break;
            }
        // Data received
            else {	//返回值>0,接收实际copy字节数
                int err = 0;
                inet_ntoa_r(((struct sockaddr_in *)&sourceAddr)->sin_addr.s_addr, addr_str, BUFFER_MAX  - 1);
                
                rx_buffer[len] = 0; // Null-terminate whatever we received and treat like a string
                printf("Received %d bytes from %s:\n", len, addr_str);
                printf("Received data: %s\n", rx_buffer);

                char *wifi_name = (char*)malloc(33);
                char *wifi_pwd = (char*)malloc(65);
                uint8_t result = analyzeWifi(rx_buffer,wifi_name,wifi_pwd);
                switch (result)
                {
                case 1:
                    err = send(sock, RESPONSE_OK, strlen(RESPONSE_OK), 0);
                    break;
                case 2:
                    err = send(sock, RESPONSE_ERR_2, strlen(RESPONSE_ERR_2), 0);
                    break;
                case 3:
                    err = send(sock, RESPONSE_ERR_3, strlen(RESPONSE_ERR_3), 0);
                    break;
                default:
                    break;
                }
                if(result==1)
                {
                    sta_config = (wifi_config_t *)malloc(sizeof(wifi_config_t));
                    memset(sta_config, 0, sizeof(wifi_config_t));
                    sprintf((char *)(sta_config->sta.ssid), wifi_name);
                    sprintf((char *)(sta_config->sta.password), wifi_pwd);
                    spi_flash_write(START_SECTOR_WIFI_INFO*0x01000, (uint32_t *)sta_config->sta.ssid, 32);
                    spi_flash_write(START_SECTOR_WIFI_INFO*0x01000+32, (uint32_t *)sta_config->sta.password, 64);

                    //设置WIFI 工作模式和station_config来设置要连接的WIFI信息
                 esp_wifi_set_mode(WIFI_MODE_STA);
                 esp_wifi_disconnect();
                 esp_wifi_set_config(ESP_IF_WIFI_STA, sta_config);
                 esp_wifi_start();
                 esp_wifi_connect();
                    free(sta_config);
                    flag_rev_wifi = TRUE;
                    break;
                }
                free(wifi_name);
                free(wifi_pwd);
                if (err < 0) 
                {
                     printf("Error occured during sending: errno %d", errno);
                     break;
                }

                //saveDeviceByDflash(deviceList);
            }
        }
    
        if (sock != -1) {
            printf("Shutting down sock and restarting...");
            shutdown(sock, 0);
            close(sock);
        }

        if (listen_sock != -1) {
            printf("Shutting down listen_sock and restarting...");
            shutdown(listen_sock, 0);
            close(listen_sock);
        }

        //flag_rev_wifi代表收到了wifi密码信息
        if(flag_rev_wifi)
        {
            break;
        }

        vTaskDelay(500 / portTICK_RATE_MS);
	}
    printf("ap vTaskDelete...\n");
    free(rx_buffer);
    free(addr_str);
    vQueueDelete(QueueStop);
    QueueStop = NULL;
    vQueueDelete(RCVQueueStop);
    RCVQueueStop = NULL;
    vTaskDelete(NULL);			//删除任务

}


/******************************************************************************
 * FunctionName : ap_task_stop
 * Description  : 停止ap任务
 * Parameters   : void
 * Returns      : pdFAIL or pdPASS 代表是否停止任务成功
*******************************************************************************/
portBASE_TYPE  ap_task_stop(void)
{
    bool ValueToSend = true;
    portBASE_TYPE xStatus;
    if (RCVQueueStop == NULL)
        return pdFAIL;

    xStatus = xQueueSend(RCVQueueStop,&ValueToSend,0);
    if (xStatus != pdPASS){
        printf("Could not send to the ap rcvqueue!\n");
        return pdFAIL;
    }

    if (QueueStop == NULL)
    return pdFAIL;

    xStatus = xQueueSend(QueueStop,&ValueToSend,0);
    if (xStatus != pdPASS){
        printf("Could not send to the ap rcvqueue!\n");
        return pdFAIL;
    }

    return pdPASS;
}

/******************************************************************************
 * FunctionName : initAp
 * Description  : 判断wifi密码是否为空
 * Parameters   : 指针指向char wifiname
 *                指针指向char wifipwd
 * Returns      : TRUE or FALSE true代表WIFI密码数据为空，代表从未配网过
*******************************************************************************/




portBASE_TYPE apInfoIsEmpty()
{

    char wifiname[32];
    char wifipwd[64];
    wifi_config_t *sta_config;

    uint32_t addr;
    addr	= START_SECTOR_WIFI_INFO*0x01000;
    spi_flash_read(addr,(uint32_t *)wifiname, 32);
    if (wifiname[0] == 255 && wifiname[1] == 255 && wifiname[2] == 255)
    {
        wifi_config_t wifi_config = {
            .ap = {
                .ssid = "myssid",
                .ssid_len = 6,
                .password = "",
                .max_connection = 1,
                .authmode = WIFI_AUTH_OPEN
            },
        };

        esp_wifi_set_mode(WIFI_MODE_AP);
        esp_wifi_set_config(ESP_IF_WIFI_AP, &wifi_config);
        esp_wifi_start();
        printf("config net is never empty!\n");
        return pdPASS;
    }
    else
    {

        addr	= START_SECTOR_WIFI_INFO*0x01000+32;
        spi_flash_read(addr,(uint32_t *)wifipwd, 64);
        esp_wifi_set_mode(WIFI_MODE_STA);
        esp_wifi_disconnect();
        sta_config = (wifi_config_t *)malloc(sizeof(wifi_config_t));
        memset(sta_config, 0, sizeof(wifi_config_t));
        sprintf((char *)(sta_config->sta.ssid), wifiname);
        sprintf((char *)(sta_config->sta.password), wifipwd);
        esp_wifi_set_config(ESP_IF_WIFI_STA, sta_config);
        esp_wifi_start();
        esp_wifi_connect();
        free(sta_config);
        return pdFAIL;
    }
}

/******************************************************************************
 * FunctionName : analyzeWifi
 * Description  : 解析AP配网时接收到的wifi数据
 * Parameters   : 
 *               
 * Returns      : uint8_t 1代表成功  2代表格式错误json串格式错误 3代表wifi密码长度超限
*******************************************************************************/
uint8_t analyzeWifi(char * json_string, char * wifiname, char * wifipwd)
{
           // 1. 解析JSON字符串为cJSON对象
       cJSON *root = cJSON_Parse(json_string);
       if (root == NULL) {
           const char *error_ptr = cJSON_GetErrorPtr();
           if (error_ptr != NULL) {
               printf("JSON analysis error，position: %s\n", error_ptr);
           }
           cJSON_Delete(root);
           return 2;
       }
    
       cJSON *name = cJSON_GetObjectItem(root, "name");
       if (name == NULL) 
       {
           printf("have no data of name!!\n");
           cJSON_Delete(root);
           return 2;
       }
       else
       {
           if (name->type == cJSON_String) 
            {
                if(strlen(name->valuestring) > 31)
                {
                    cJSON_Delete(root);
                    return 3;
                }
                printf("name: %s\n", name->valuestring);
            }
            else
            {
                printf("name type error!!\n");
                cJSON_Delete(root);
                return 2;
            }
       }

       cJSON *pwd = cJSON_GetObjectItem(root, "pwd");
       if (pwd == NULL) {
           printf("have no data of pwd!!\n");
           cJSON_Delete(root);
           return 2;
       }
       else
       {
            if (pwd->type == cJSON_String) 
            {
                if(strlen(pwd->valuestring) > 63)
                {
                    cJSON_Delete(root);
                    return 3;
                }
                printf("pwd: %s\n", pwd->valuestring);
            }
            else
            {
                printf("pwd type error!!\n");
                cJSON_Delete(root);
                return 2;
            }
       }

    strncpy(wifiname, name->valuestring, strlen(name->valuestring));
    strncpy(wifipwd, pwd->valuestring, strlen(pwd->valuestring));
    wifiname[strlen(name->valuestring)] = '\0';
    wifipwd[strlen(pwd->valuestring)] = '\0';

    cJSON_Delete(root);
    return 1;
}

/******************************************************************************
 * FunctionName : analyze
 * Description  : 解析AP配网时接收到的数据 debug
 * Parameters   : 
 *               
 * Returns      : 
*******************************************************************************/
void analyze(char * json_string)
{
       uint16_t i=0;
       // 示例JSON字符串（模拟API响应或文件内容）
       //const char *json_string = "{\"name\":\"Alice\",\"age\":25,\"is_student\":false,\"courses\":[\"Math\",\"Physics\"],\"address\":{\"city\":\"Beijing\",\"zip\":\"100000\"}}";
 
       // 1. 解析JSON字符串为cJSON对象
       cJSON *root = cJSON_Parse(json_string);
       if (root == NULL) {
           const char *error_ptr = cJSON_GetErrorPtr();
           if (error_ptr != NULL) {
               printf("JSON analysis error，position: %s\n", error_ptr);
           }
           return;
       }
    
       // 2. 提取基本类型字段
       cJSON *name = cJSON_GetObjectItem(root, "name");
       if (name->type == cJSON_String) {
           printf("Name: %s\n", name->valuestring);
       }
    
       cJSON *age = cJSON_GetObjectItem(root, "age");
       if (age->type == cJSON_Number) {
           printf("Age: %d\n", age->valueint);
       }
    
       cJSON *is_student = cJSON_GetObjectItem(root, "is_student");
       if (is_student->type == cJSON_True || is_student->type == cJSON_False) {
           printf("Is Student: %s\n", is_student->valueint ? "true" : "false");
       }
    
       // 3. 处理数组
       cJSON *courses = cJSON_GetObjectItem(root, "courses");
       if (courses->type == cJSON_Array) {
           uint16_t size = cJSON_GetArraySize(courses);
           printf("Courses:\n");
           for ( i = 0; i < size; i++)
           {
            cJSON *course = NULL;
            course = cJSON_GetArrayItem(courses,i);
            if (course->type == cJSON_String) {
                printf("  - %s\n", course->valuestring);
            }
            // cJSON_Delete(course);
           }
        
       }
    
       // 4. 处理嵌套对象
       cJSON *address = cJSON_GetObjectItem(root, "address");
       if (address->type == cJSON_Object) {
           cJSON *city = cJSON_GetObjectItem(address, "city");
           cJSON *zip = cJSON_GetObjectItem(address, "zip");
           if (city->type == cJSON_String && zip->type == cJSON_String) {
               printf("Address: %s, Zip: %s\n", city->valuestring, zip->valuestring);
           }
        //    cJSON_Delete(city);
        //    cJSON_Delete(zip);
       }
    
       // 5. 清理内存
       cJSON_Delete(root);
    //    cJSON_Delete(name);
    //    cJSON_Delete(age);
    //    cJSON_Delete(is_student);
    //    cJSON_Delete(courses);
    //    cJSON_Delete(address);
}